(function (global, factory) {
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
	typeof define === 'function' && define.amd ? define(['exports'], factory) :
	(factory((global.pip = global.pip || {})));
}(this, (function (exports) { 'use strict';

//
// 配合php项目经常会用到的方法
//

/**
 * 当前时间戳
 * @return {Int} PHP当前时间戳
 */


/**
 * 字符串转时间戳
 * @param  {String} str 时间日期字符串
 * @return {Int}     PHP对应时间戳
 */


/**
 * 时间戳转字符串
 * @param  {Int} ts    php时间戳
 * @param  {Object} options 设置对象
 * @return {String}
 */

//
// 一些对字符串的处理操作
//


/**
 * 去html标签跟特殊符号
 * @param  {String} mixed 包含标签跟符号的原始字符串
 * @return {String}       过滤后的字符串
 */


/**
 * 截取字符串超出部分
 * @param  {String} str 原始字符串内容
 * @param  {Int} max 最多显示字数
 * @return {String}     截断结果
 */

//
// 一些数字的处理
//


/**
 * 金钱加,分割
 * @param  {Float} num 金额可能包含小数
 * @return {String}       过滤后的金额
 */

//
// 一些对数组的处理操作
//


/**
 * 数组里的元素位置对换
 * @param  {Array} arr 要操作的数组
 * @param  {Int} from 从哪里
 * @param {Int} to  调换到哪里
 * @return {Array}
 */
var move = function move(arr, from, to) {
  arr.splice(to, 0, arr.splice(from, 1)[0]);
  return arr;
};

var _arr = Object.freeze({
	move: move
});

//
// 杂类函数
//


/**
 * 运行时间测试
 * @param  {String} name 测试名称
 * @return {Emitter}
 */

//
// Redux库便捷函数
//

/**
 * 创建 redux action
 * @param  {String} type 动作类型
 * @param  {Mixed} data 传递数据
 * @return {Object}
 */
var createAction = function createAction(type) {
  for (var _len = arguments.length, data = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    data[_key - 1] = arguments[_key];
  }

  return function () {
    for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
      args[_key2] = arguments[_key2];
    }

    var action = { type: type };
    data.forEach(function (arg, i) {
      action[data[i]] = args[i];
    });
    return action;
  };
};

var createReducer = function createReducer(initState, handlers) {
  return function () {
    var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initState;
    var action = arguments[1];

    if (handlers.hasOwnProperty(action.type)) {
      return handlers[action.type](state, action);
    } else {
      return state;
    }
  };
};

var _redux = Object.freeze({
	createAction: createAction,
	createReducer: createReducer
});

// 附加函数组
// export const num = _num;
// export const utils = _utils;
// export const str = _str;
// export const php = _php;
var arr = _arr;
var redux = _redux;

// 核心函数组


/**
 * 获取IE版号或edge
 */
var ie = function ie() {
  var v = 3,
      div = document.createElement('div'),
      all = div.getElementsByTagName('i');
  while (div.innerHTML = '<!--[if gt IE ' + ++v + ']><i></i><![endif]-->', all[0]) {}
  v = v > 4 ? v : false;
  if (document.all && !v) v = 10;
  if ('ActiveXObject' in window && !v) v = 11;
  if (window.navigator.appVersion.search('Edge') !== -1) {
    v = 'edge';
  }
  return v;
};

/**
 * xmlhttp 请求
 * @param  {string} url     请求地址
 * @param  {object} options 设置
 * @return {emitter}
 */
var xhr = function xhr(url) {
  var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  var opts = assign({
    method: 'GET', // 请求方法
    type: 'json', // 内容类型
    cache: false,
    payload: false,
    formdata: false,
    withCredentials: false,
    showProgress: false,
    data: {},
    headers: {}
  }, options),
      xhr = void 0,
      progress = 0,
      send_data = [],
      emt = emitter(),
      has_q = url.split('/').pop().search(/\?/) !== -1;
  // 是否有缓存
  if (!opts.cache) {
    url += (has_q ? '&' : '?') + '_=' + Math.random();
    has_q = true;
  }
  // 整理发送数据
  if (opts.formdata) {
    send_data = opts.data;
  } else if (serialize(opts.data) !== '') {
    send_data.push(serialize(opts.data));
  }
  // 如果是put /post 则用formdata
  if (/^put$|^post$/i.test(opts.method) && !opts.payload) {
    opts.headers['Content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
  } else if (send_data.length > 0) {
    if (!opts.formdata) url += (has_q ? '&' : '?') + send_data;
  }
  xhr = new XMLHttpRequest();
  xhr.open(opts.method, url, true);
  for (var k in opts.headers) {
    xhr.setRequestHeader(k, opts.headers[k]);
  }
  xhr.withCredentials = opts.withCredentials;
  // 如果支持进度条
  if (opts.showProgress) {
    var progressFn = function progressFn(e) {
      if (e.lengthComputable) {
        progress = Math.round(e.loaded * 100 / e.total);
        emt.emit('progress', progress);
      }
    };
    if (xhr.upload) {
      xhr.upload.addEventListener('progress', progressFn, false);
    }
    xhr.addEventListener('progress', progressFn, false);
  }
  xhr.addEventListener('load', function (e) {
    var res = void 0;
    if (e.target.status === 200 || e.target.status === 304) {
      res = e.target.responseText;
      if (opts.type === 'json') {
        try {
          res = JSON.parse(res);
        } catch (e) {
          throw new Error('JSON数据解析失败');
        }
      }
      emt.emit('done', res);
    } else {
      emt.emit('error', e.target.status);
    }
  }, { once: true });

  xhr.addEventListener('error', function (e) {
    emt.emit('error', e.target.status);
  }, { once: true });

  xhr.addEventListener('loadend', function () {
    emt.emit('complete');
  }, { once: true });

  emt.once('abort', function () {
    xhr.abort();
  });

  xhr.send(send_data);

  return emt;
};

/**
 * 资源加载器，按顺序加载，并行加载的放入一个数组中
 * @param  {Mixed} batches 文件组
 * @return {emitter}
 */
// 已经加载的文件名(作用：如果有重复的文件可以忽略加载)
var _PIP_FILELOADED = [];
var load = function load() {
  for (var _len = arguments.length, batches = Array(_len), _key = 0; _key < _len; _key++) {
    batches[_key] = arguments[_key];
  }

  var emt = emitter(),

  // 开始索引
  index = 0,

  // 结束
  endIndex = batches.length || 0,

  // 支持的文件后缀
  fileSupport = {
    js: {
      tag: 'script',
      from: 'src',
      attrs: { defer: true }
    },
    css: {
      tag: 'link',
      from: 'href',
      attrs: { rel: 'stylesheet' }
    }
  },

  // 私有方法
  fn = {
    // 获取文件名
    fileName: function fileName(url) {
      return url.split('/').pop().split('?')[0];
    },
    // 获取文件后缀
    fileExt: function fileExt(url) {
      return url.split('.').pop().split('?')[0];
    },
    fileLoad: function fileLoad(url) {
      var emt2 = emitter(),
          ext = fn.fileExt(url),
          file = void 0,
          el = void 0;
      if (!fileSupport[ext]) {
        throw new Error(ext + '\u683C\u5F0F\u6587\u4EF6\u4E0D\u5141\u8BB8\u52A0\u8F7D');
      }
      file = fileSupport[ext];
      el = document.createElement(file.tag);
      el[file.from] = url;
      Object.keys(file.attrs).forEach(function (key) {
        el[key] = file.attrs[key];
      });
      el.addEventListener('load', function () {
        emt2.emit('done', url);
      }, false);
      el.addEventListener('error', function () {
        emt2.emit('error', url);
      }, false);
      document.head.appendChild(el);
      return emt2;
    },
    checker: function checker(batchFileLoaded, n, emt) {
      if (batchFileLoaded.length === n) {
        index++;
        if (index === endIndex) {
          setTimeout(function () {
            emt.emit('done', batchFileLoaded);
          }, 1);
          return;
        }
        fn.batchLoad(batches[index]);
      }
    },
    batchLoad: function batchLoad(batch) {
      var n = void 0,
          // 组里有多少文件
      batchFileLoaded = []; // 组中已经成功加载的文件
      if (typeOf(batch) === 'String') {
        batch = [batch];
      }
      n = batch.length;
      batch.forEach(function (url) {
        if (_PIP_FILELOADED.indexOf(url.split('?')[0]) !== -1) {
          // 有重复的就忽略
          batchFileLoaded.push(url.split('?')[0]);
          fn.checker(batchFileLoaded, n, emt);
          return;
        }
        fn.fileLoad(url).on('done', function (file) {
          _PIP_FILELOADED.push(file.split('?')[0]);
          batchFileLoaded.push(url.split('?')[0]);
          fn.checker(batchFileLoaded, n, emt);
        }).on('error', function (file) {
          emt.emit('error', file);
        });
      });
    }
  };

  if (endIndex === 0) {
    throw new Error('无资源加载');
  }

  fn.batchLoad(batches[index]);

  return emt;
};

/**
 * object => serialize
 * @param  {Object} obj
 * @return {String}
 */
var serialize = function serialize() {
  var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  return Object.keys(obj).map(function (k) {
    return encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]);
  }).join('&');
};

/**
 * hash search 转对象
 * ?a=a&b=b => {a:'a',b:'b'}
 * @param  {String} hash
 * @return {Object}
 */
var search2obj = function search2obj() {
  var hash = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

  var ret = {},
      seg = decodeURIComponent(hash).replace(/^\?/, '').split('&'),
      len = seg.length,
      i = 0,
      s = void 0;
  for (; i < len; i++) {
    if (!seg[i]) {
      continue;
    }
    s = seg[i].split('=');
    ret[s[0]] = s[1];
  }
  return ret;
};

/**
 * 对象数据扩充
 * @param  {Object} obj 目标对象
 * @param  {Object} ext 扩充对象
 * @return {Object}
 */
var assign = function assign() {
  var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
  var ext = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

  for (var k in ext) {
    if (ext.hasOwnProperty(k)) {
      obj[k] = ext[k];
    }
  }
  return obj;
};

/**
 * 优化 typeof 获取未知对象类型
 * @param  {Mixed} mixed
 * @return {String}       Number|String|Object|Array|Function
 */
var typeOf = function typeOf(mixed) {
  return Object.prototype.toString.apply(mixed).match(/\[object (\w+)\]/)[1];
};

/**
 * 只是为了读取对象数据避免被覆盖数据用的copy
 */
var objDataCopy = function objDataCopy(obj) {
  return JSON.parse(JSON.stringify(obj));
};

/**
 * Cookie操作
 */
var cookie = {
  /**
   * 设置 cookie
   * @param  {string} name  项
   * @param  {String} value 值
   * @param  {Object} opts  扩展配置
   * @return {null}
   */
  set: function set(name) {
    var value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
    var options = arguments[2];

    var data = {},
        cookies = [],
        opts = assign({
      path: '/',
      domain: ''
    }, options);
    if (!name || /^(?:expires|max\-age|path|domain|secure)$/i.test(name)) {
      throw new Error('Cookie名称不能为保留字');
    }
    data[encodeURIComponent(name)] = encodeURIComponent(value);
    if (opts['expires']) {
      throw new Error('使用max-age替换expires');
    }
    for (var opt in opts) {
      data[opt] = opts[opt];
    }
    for (var key in data) {
      cookies.push(key + '=' + data[key]);
    }
    cookies = cookies.join('; ');
    document.cookie = cookies + ';';
  },


  /**
   * 删除cookie某项
   * @param  {string} name
   * @return {null}
   */
  remove: function remove(name) {
    this.set(name, '', {
      'max-age': 0
    });
  },


  /**
   * 获取cookie某项
   * @param  {String} key [description]
   * @return {[type]}      [description]
   */
  get: function get() {
    var key = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';

    var result = void 0;
    document.cookie.split('; ').forEach(function (_cookie) {
      var name = _cookie.split('=')[0],
          value = _cookie.split('=')[1];
      if (key !== '' && key === name) {
        result = decodeURIComponent(value);
      }
    });
    return result;
  }
};

/**
 * 监听模式封装
 */
var emitter = function emitter() {
  var el = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};


  /**
   * 所有监听中的回调函数
   * @type {Object}
   */
  var _callbacks = {};

  /**
   * object defineProperty 默认
   * writable : false, configurable : false, enumerable : false
   * 避免被复写
   * 自定义事件
   */
  Object.defineProperty(el, 'on', {
    value: function value(event, fn) {
      if (typeof fn == 'function') {
        (_callbacks[event] = _callbacks[event] || []).push(fn);
      }
      return el;
    }
  });

  Object.defineProperty(el, 'once', {
    value: function value(event, fn) {
      var on = function on() {
        for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
          args[_key2] = arguments[_key2];
        }

        el.off(event, on);
        fn.apply(el, args);
      };
      return el.on(event, on);
    }
  });

  /**
   * 解除某自定义事件
   */
  Object.defineProperty(el, 'off', {
    value: function value(event, fn) {
      if (event === '*' && !fn) _callbacks = {};else {
        if (fn) {
          for (var _i in _callbacks[event]) {
            if (_callbacks[event][_i] == fn) _callbacks[event].splice(_i, 1);
          }
        } else delete _callbacks[event];
      }
      return el;
    }
  });

  /**
   * 触发某自定义事件
   */
  Object.defineProperty(el, 'emit', {
    value: function value(event) {
      for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
        args[_key3 - 1] = arguments[_key3];
      }

      var fns = (_callbacks[event] || []).slice(0);
      fns.forEach(function (_fn) {
        _fn.apply(el, args);
      });
      if (_callbacks['*'] && event !== '*') el.emit.apply(el, ['*', event].concat(args));
      return el;
    }
  });

  return el;
};

exports.arr = arr;
exports.redux = redux;
exports.ie = ie;
exports.xhr = xhr;
exports.load = load;
exports.serialize = serialize;
exports.search2obj = search2obj;
exports.assign = assign;
exports.typeOf = typeOf;
exports.objDataCopy = objDataCopy;
exports.cookie = cookie;
exports.emitter = emitter;

Object.defineProperty(exports, '__esModule', { value: true });

})));
